package edison.jcr;

import java.util.ArrayList;
import java.util.List;

import javax.jcr.RangeIterator;
import javax.persistence.TypedQuery;

public abstract class RangeIteratorImpl<T> implements RangeIterator {

	private static final int CACHE_SIZE = 10;

	protected final TypedQuery<T> query;
	protected final TypedQuery<Long> sizeQuery;
	protected int position = 0;
	protected final SessionContext context;
	protected final List<T> cache = new ArrayList<T>(CACHE_SIZE);

	public RangeIteratorImpl(SessionContext context, TypedQuery<T> query, TypedQuery<Long> sizeQuery) {
		this.query = query;
		this.sizeQuery = sizeQuery;
		this.context = context;
	}

	protected void refreshCache() {
		if (position % CACHE_SIZE == 0) {
			List<T> result = query.setFirstResult(position).getResultList();
			cache.clear();
			cache.addAll(result);
		}
	}

	protected abstract Object cast(T bean);

	public boolean hasNext() {
		refreshCache();
		return cache.size() > 0;
	}

	public Object next() {
		refreshCache();
		int cachePosition = position % CACHE_SIZE;
		T bean = cache.get(cachePosition);
		position++;
		return cast(bean);
	}

	public void remove() {
		throw new UnsupportedOperationException();
	}

	public void skip(long skipNum) {
		query.setFirstResult((int) skipNum);
		position += skipNum;
	}

	public long getSize() {
		return sizeQuery.getSingleResult();
	}

	public long getPosition() {
		return position;
	}
}